/*
 * Copyright (c) 2013-2018 上海汇数数据. All rights reserved.
 * @(#) Splitters.java 2018-08-06 17:27
 */

package cn.jh.common.core.base;

import com.google.common.base.CharMatcher;
import com.google.common.base.Splitter;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Maps;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;

import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;


/**
 * Guava 库中的{@code Splitter}，字符串分隔器帮助类。
 *
 * @author Fuchun
 * @since 1.0
 */
public abstract class Splitters {

    private static final Map<String, Splitter> SPLITTER_MAP = Maps.newHashMap();

    private static Splitter createConstant(String separator) {
        return addKnownSplitter(separator, Splitter.on(separator));
    }

    private static Splitter createConstant(Pattern separator) {
        return addKnownSplitter(separator.pattern(), Splitter.on(separator));
    }

    private static String getSplitterKey(
            String separator, boolean trimResults, boolean omitEmptyStrings, Integer limit) {
        String trim = trimResults ? "TRIM" : null;
        String oe = omitEmptyStrings ? "OMIT_EMPTY" : null;
        String fl = (limit != null && limit > 0) ? String.format("LIMIT:%s", limit) : null;
        return Joiners.colon().join(separator, trim, oe, fl);
    }

    private static Splitter createConstant(
            String separator, boolean trimResults, boolean omitEmptyStrings, Integer limit) {
        String key = getSplitterKey(separator, trimResults, omitEmptyStrings, limit);
        Splitter splitter = Splitter.on(separator);
        if (trimResults) splitter = splitter.trimResults();
        if (omitEmptyStrings) splitter = splitter.omitEmptyStrings();
        if (limit != null) splitter = splitter.limit(limit);
        return addKnownSplitter(key, splitter);
    }

    private static Splitter addKnownSplitter(String key, Splitter splitter) {
        SPLITTER_MAP.put(key, splitter);
        return splitter;
    }

    protected static Splitter findOrCreate(String separator) {
        checkNotNull(separator, "separator");
        Splitter splitter = SPLITTER_MAP.get(separator);
        if (splitter == null) {
            splitter = createConstant(separator);
        }
        return splitter;
    }

    protected static Splitter findOrCreate(Pattern separator) {
        checkNotNull(separator, "separator");
        Splitter splitter = SPLITTER_MAP.get(separator.pattern());
        if (splitter == null) {
            splitter = createConstant(separator);
        }
        return splitter;
    }

    @SuppressWarnings("unused")
    protected static Splitter findOrCreate(
            String separator, boolean trimResults, boolean omitEmptyStrings, Integer limit) {
        checkNotNull(separator, "separator");
        String key = getSplitterKey(separator, trimResults, omitEmptyStrings, limit);
        Splitter splitter = SPLITTER_MAP.get(key);
        if (splitter == null) {
            splitter = createConstant(separator, trimResults, omitEmptyStrings, limit);
        }
        return splitter;
    }

    /**
     * 使用 " "(空格) 字符作为分隔符的字符串分隔器。
     */
    public static final Splitter BLANK_SPLITTER = createConstant(" ");

    /**
     * 使用 " "(空格) 字符作为分隔符的字符串分隔器。
     * 分隔时将忽略空字符串，分隔后的字符串将去除前导和后导空格。
     */
    public static final Splitter BLANK_TOE_SPLITTER = createConstant(" ", true, true, null);

    /**
     * 使用 ","(逗号) 字符作为分隔符的字符串分隔器。
     */
    public static final Splitter COMMA_SPLITTER = createConstant(",");

    /**
     * 使用 ","(逗号) 字符作为分隔符的字符串分隔器。
     * 分隔时将忽略空字符串，分隔后的字符串将去除前导和后导空格。
     */
    public static final Splitter COMMA_TOE_SPLITTER = createConstant(",", true, true, null);

    /**
     * 使用 ";"(分号) 字符作为分隔符的字符串分隔器。
     */
    public static final Splitter SEMICOLON_SPLITTER = createConstant(";");

    /**
     * 使用 ";"(分号) 字符作为分隔符的字符串分隔器。
     * 分隔时将忽略空字符串，分隔后的字符串将去除前导和后导空格。
     */
    public static final Splitter SEMICOLON_TOE_SPLITTER = createConstant(";", true, true, null);

    /**
     * 使用 ":"(冒号) 字符作为分隔符的字符串分隔器。
     */
    public static final Splitter COLON_SPLITTER = createConstant(":");

    /**
     * 使用 ":"(冒号) 字符作为分隔符的字符串分隔器。
     * 分隔时将忽略空字符串，分隔后的字符串将去除前导和后导空格。
     */
    public static final Splitter COLON_TOE_SPLITTER = createConstant(":", true, true, null);

    /**
     * 使用 "/"(斜线) 字符作为分隔符的字符串分隔器。
     */
    public static final Splitter SLASH_SPLITTER = createConstant("/");

    /**
     * 使用 "/"(斜线) 字符作为分隔符的字符串分隔器。
     * 分隔时将忽略空字符串，分隔后的字符串将去除前导和后导空格。
     */
    public static final Splitter SLASH_TOE_SPLITTER = createConstant("/", true, true, null);

    /**
     * 使用 "\\"(反斜线) 字符作为分隔符的字符串分隔器。
     */
    public static final Splitter BACKSLASH_SPLITTER = createConstant("\\");

    /**
     * 使用 "\\"(反斜线) 字符作为分隔符的字符串分隔器。
     * 分隔时将忽略空字符串，分隔后的字符串将去除前导和后导空格。
     */
    public static final Splitter BACKSLASH_TOE_SPLITTER = createConstant("\\", true, true, null);

    /**
     * 使用 "&"(与符号) 字符作为分隔符的字符串分隔器。
     */
    public static final Splitter AND_SPLITTER = createConstant("&");

    /**
     * 使用 "&"(与符号) 字符作为分隔符的字符串分隔器。
     * 分隔时将忽略空字符串，分隔后的字符串将去除前导和后导空格。
     */
    public static final Splitter AND_TOE_SPLITTER = createConstant("&", true, true, null);

    /**
     * 使用 "\t"(制表符) 字符作为分隔符的字符串分隔器。
     */
    public static final Splitter TAB_SPLITTER = createConstant("\t");

    /**
     * 使用 "\t"(制表符) 字符作为分隔符的字符串分隔器。
     * 分隔时将忽略空字符串，分隔后的字符串将去除前导和后导空格。
     */
    public static final Splitter TAB_TOE_SPLITTER = createConstant("\t", true, true, null);

    /**
     * 使用 "\n"(换行符) 字符作为分隔符的字符串分隔器。
     */
    public static final Splitter NL_SPLITTER = createConstant("\n");

    /**
     * 使用 "\n"(换行符) 字符作为分隔符的字符串分隔器。
     * 分隔时将忽略空字符串，分隔后的字符串将去除前导和后导空格。
     */
    public static final Splitter NL_TOE_SPLITTER = createConstant("\n", true, true, null);

    /**
     * 使用 "_"(下划线) 字符作为分隔符的字符串分隔器。与{@link Joiners#underline()} 对应。
     */
    public static final Splitter UNDERLINE_SPLITTER = createConstant("_");

    /**
     * 使用 "_"(下划线) 字符作为分隔符的字符串分隔器。
     * 分隔时将忽略空字符串，分隔后的字符串将去除前导和后导空格。
     */
    public static final Splitter UNDERLINE_TOE_SPLITTER = createConstant("_", true, true, null);

    /**
     * 使用 "+"(加号) 字符作为分隔符的字符串分隔器。与{@link Joiners#plus()} 对应。
     */
    public static final Splitter PLUS_SPLITTER = createConstant("+");

    /**
     * 使用 "+"(加号) 字符作为分隔符的字符串分隔器。
     * 分隔时将忽略空字符串，分隔后的字符串将去除前导和后导空格。
     */
    public static final Splitter PLUS_TOE_SPLITTER = createConstant("+", true, true, null);

    /**
     * 使用 "-"(减号) 字符作为分隔符的字符串分隔器。与{@link Joiners#minus()} 对应。
     */
    public static final Splitter MINUS_SPLITTER = createConstant("-");

    /**
     * 使用 "-"(减号) 字符作为分隔符的字符串分隔器。
     * 分隔时将忽略空字符串，分隔后的字符串将去除前导和后导空格。
     */
    public static final Splitter MINUS_TOE_SPLITTER = createConstant("-", true, true, null);

    /**
     * 使用 "|"(竖线) 字符作为分隔符的字符串分隔器。与{@link Joiners#vertical()} 对应。
     */
    public static final Splitter VERTICAL_SPLITTER = createConstant("|");

    /**
     * 使用 "|"(竖线) 字符作为分隔符的字符串分隔器。
     * 分隔时将忽略空字符串，分隔后的字符串将去除前导和后导空格。
     */
    public static final Splitter VERTICAL_TOE_SPLITTER = createConstant("|", true, true, null);

    /**
     * 使用 "=" 作为键与值的分隔符，"&" 作为键值对间的分隔符的字符串分隔器。
     */
    public static final Splitter.MapSplitter QUERY_SPLITTER = AND_TOE_SPLITTER.withKeyValueSeparator("=");

    /**
     * 使用 "=" 作为键与值的分隔符，";" 作为键值对间的分隔符的字符串分隔器。
     */
    public static final Splitter.MapSplitter SEMICOLON_MAP_SPLITTER = SEMICOLON_TOE_SPLITTER.withKeyValueSeparator("=");

    /**
     * 使用 "=" 作为键与值的分隔符，"," 作为键值对间的分隔符的字符串分隔器。
     */
    private static final Splitter.MapSplitter COMMA_MAP_SPLITTER = COMMA_TOE_SPLITTER.withKeyValueSeparator("=");

    public static Splitter toeSplitter(String separator) {
        return findOrCreate(separator, true, true, null);
    }

    public static Splitter.MapSplitter commaEqualMap() {
        return COMMA_MAP_SPLITTER;
    }

    @Contract("null, _ -> fail")
    public static Iterable<String> split(CharSequence sequence, String separator) {
        checkArgument(sequence != null, "sequence");
        return findOrCreate(separator).split(sequence);
    }

    @Contract("null, _ -> fail")
    public static Iterable<String> split(CharSequence sequence, char separator) {
        checkArgument(sequence != null, "sequence");
        return findOrCreate(Character.toString(separator)).split(sequence);
    }

    @Contract("null, _ -> fail; _, null -> fail")
    public static Iterable<String> split(CharSequence sequence, Pattern separatorPattern) {
        checkArgument(sequence != null, "sequence");
        return findOrCreate(separatorPattern).split(sequence);
    }

    @Contract("null, _ -> fail; _, null -> fail")
    public static List<String> splitToList(CharSequence sequence, String separator) {
        checkArgument(sequence != null, "sequence");
        return findOrCreate(separator).splitToList(sequence);
    }

    @Contract("null, _ -> fail")
    public static List<String> splitToList(CharSequence sequence, char separator) {
        checkArgument(sequence != null, "sequence");
        return findOrCreate(Character.toString(separator)).splitToList(sequence);
    }

    @Contract("null, _ -> fail; _, null -> fail")
    public static List<String> splitToList(CharSequence sequence, Pattern separatorPattern) {
        checkArgument(sequence != null, "sequence");
        return findOrCreate(separatorPattern).splitToList(sequence);
    }

    /**
     * 返回给定路径的目录名称列表（最后一个元素可能是目录或文件名称）。
     * 如果给定的是Windows系统下的路径，则第一个元素可能会是（C:、D:、..）
     * <pre>{@code
     * List<String> parts = Splitters.getPathParts("/etc/sysconfig/i18n");
     * // parts -> ["etc", "sysconfig", "i18n"]
     *
     * List<String> parts = Splitters.getPathParts("D:\\foo\\bar\\");
     * // parts -> ["D:", "foo", "bar"]
     * }</pre>
     *
     * @param path 给定的路径。
     * @return 返回给定路径的目录名称列表。
     */
    @NotNull
    public static List<String> getPathParts(String path) {
        if (path == null || path.isEmpty()) {
            return ImmutableList.of();
        }
        String target = path.trim().replace('\\', '/');
        target = CharMatcher.is('/').trimFrom(target);
        // splitToList 已经被标注为 Beta
        return SLASH_SPLITTER.splitToList(target);
    }

    /**
     * 解析查询字符串，以 map 方式返回参数信息。
     * <pre>{@code
     * Map<String, String> params = Splitters.getParams("foo=val1&bar=val2");
     * // params = {"foo": "val1", "bar": "val2"}
     * }</pre>
     *
     * @param queryString 查询字符串。
     * @return 返回参数信息。
     */
    @NotNull
    public static Map<String, String> getParams(String queryString) {
        if (queryString == null || queryString.isEmpty()) {
            return ImmutableMap.of();
        }
        return QUERY_SPLITTER.split(queryString);
    }
}
